home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Magazine / Online / QMail / source / qlist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-15  |  8.9 KB  |  334 lines

  1. #include "sig.h"
  2. #include "readwrite.h"
  3. #include "substdio.h"
  4. #include "stralloc.h"
  5. #include "subfd.h"
  6. #include "getln.h"
  7. #include "alloc.h"
  8. #include "str.h"
  9. #include "env.h"
  10. #include "hfield.h"
  11. #include "case.h"
  12. #include "token822.h"
  13. #include "error.h"
  14. #include "gen_alloc.h"
  15. #include "gen_allocdefs.h"
  16. #include "headerbody.h"
  17. #include "exit.h"
  18. #include "open.h"
  19. #include "lock.h"
  20. #include "qmail.h"
  21.  
  22. #define ADDRLIMIT 100
  23.  
  24. void die() { _exit(100); }
  25. void die_temp() { _exit(111); }
  26. void die_nomem() {
  27.  substdio_putsflush(subfderr,"qlist: fatal: out of memory\n"); die_temp(); }
  28. void die_fork() {
  29.  substdio_putsflush(subfderr,"qlist: fatal: unable to fork\n"); die_temp(); }
  30. void die_nolock() {
  31.  substdio_putsflush(subfderr,"qlist: fatal: unable to open lock file\n"); die_temp(); }
  32. void die_boing() {
  33.  substdio_putsflush(subfderr,"qlist: fatal: I don't reply to bounces\n"); die(); }
  34. void die_badaddr() {
  35.  substdio_putsflush(subfderr,"qlist: fatal: sorry, I'm not allowed to use that address\n"); die(); }
  36. void die_qqperm() {
  37.  substdio_putsflush(subfderr,"qlist: fatal: permanent qmail-queue error\n"); die(); }
  38. void die_qqtemp() {
  39.  substdio_putsflush(subfderr,"qlist: fatal: temporary qmail-queue error\n"); die_temp(); }
  40. void die_usage() {
  41.  substdio_putsflush(subfderr,
  42.  "qlist: usage: qlist user-list@host user-list-request@host .qmail-list .qmail-list-request .qtemp-list owner [moreinfo]\n"); die(); }
  43. void die_read() {
  44.  if (errno == error_nomem) die_nomem();
  45.  substdio_putsflush(subfderr,"qlist: fatal: read error\n"); die_temp(); }
  46. void doordie(sa,r) stralloc *sa; int r; {
  47.  if (r == 1) return; if (r == -1) die_nomem();
  48.  substdio_putsflush(subfderr,"qlist: fatal: unable to parse this: ");
  49.  substdio_putflush(subfderr,sa->s,sa->len); die(); }
  50.  
  51. int subjectaction = 0;
  52. int numcommands;
  53.  
  54. int fdlock;
  55.  
  56. struct qmail qqt;
  57.  
  58. char *target;
  59. char *listathost;
  60. char *requestathost;
  61. char *qmaillist;
  62. char *qmailrequest;
  63. char *qtemplist;
  64. char *owner;
  65. char *moreinfo;
  66.  
  67. char *dtline;
  68. char *returnpath;
  69. stralloc safrom = {0};
  70. stralloc sart = {0};
  71.  
  72. int rwfrom(addr) token822_alloc *addr; { token822_reverse(addr);
  73.  if (token822_unquote(&safrom,addr) != 1) die_nomem();
  74.  token822_reverse(addr); return 1; }
  75. int rwrt(addr) token822_alloc *addr; { token822_reverse(addr);
  76.  if (token822_unquote(&sart,addr) != 1) die_nomem();
  77.  token822_reverse(addr); return 1; }
  78.  
  79. GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
  80. GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
  81. static stralloc sauninit = {0}; saa savedh = {0};
  82. void savedh_append(h) stralloc *h; {
  83.  if (!saa_readyplus(&savedh,1)) die_nomem(); savedh.sa[savedh.len] = sauninit;
  84.  if (!stralloc_copy(savedh.sa + savedh.len,h)) die_nomem(); ++savedh.len; }
  85. void savedh_print() { int i; for (i = 0;i < savedh.len;++i)
  86.  qmail_put(&qqt,savedh.sa[i].s,savedh.sa[i].len); }
  87.  
  88. void finishheader()
  89. {
  90.  int i;
  91.  
  92.  if (sart.s)
  93.   { if (!stralloc_0(&sart)) die_nomem(); target = sart.s; }
  94.  else if (safrom.s)
  95.   { if (!stralloc_0(&safrom)) die_nomem(); target = safrom.s; }
  96.  else
  97.    target = returnpath;
  98.  
  99.  for (i = 0;target[i];++i)
  100.    if (target[i] == '\n')
  101.      die_badaddr();
  102.  if (i > ADDRLIMIT) die_badaddr();
  103.  if (str_equal(target,"")) die_boing();
  104.  if (str_equal(target,"#@[]")) die_boing();
  105.  
  106.  if (qmail_open(&qqt) == -1) die_fork();
  107.  
  108.  qmail_puts(&qqt,dtline);
  109.  savedh_print();
  110.  
  111.  qmail_puts(&qqt,"\n***** Text inserted by ");
  112.  qmail_puts(&qqt,requestathost);
  113.  qmail_puts(&qqt,"\n\
  114. *\n\
  115. * Hi! This is the qlist program. I'm handling subscriptions for the\n\
  116. * ");
  117.  qmail_puts(&qqt,listathost);
  118.  qmail_puts(&qqt," mailing list.\n\
  119. *\n");
  120.  if (moreinfo)
  121.   {
  122.    qmail_puts(&qqt,"* ");
  123.    qmail_puts(&qqt,moreinfo);
  124.    qmail_puts(&qqt,"\n*\n");
  125.   }
  126.  qmail_puts(&qqt,"* My human owner is ");
  127.  qmail_puts(&qqt,owner);
  128.  qmail_puts(&qqt,".\n\
  129. *\n\
  130. * To the recipient: This message was sent to me on your behalf. (Your\n\
  131. * address was listed in the Reply-To or From field.) For security,\n\
  132. * I'm forwarding this message to you, along with my notes.\n\
  133. *\n\
  134. * Anyway, to subscribe, send me an empty message. To unsubscribe, send me\n\
  135. * a message with the word UNSUBSCRIBE at the beginning of a line. Remember,\n\
  136. * my address is ");
  137.  qmail_puts(&qqt,requestathost);
  138.  qmail_puts(&qqt,".\n\
  139. *\n\
  140. * Now I'll look for requests inside this message...\n\
  141. *\n\
  142. *****\n");
  143. }
  144.  
  145. substdio subin; char subinbuf[SUBSTDIO_INSIZE];
  146. substdio subout; char suboutbuf[SUBSTDIO_OUTSIZE];
  147. stralloc subline = {0};
  148. void subscribe(flagadd)
  149. int flagadd;
  150. {
  151.  int fdin;
  152.  int fdout;
  153.  int match;
  154.  int flagwasthere;
  155.  
  156.  ++numcommands;
  157.  
  158.  if (lock_ex(fdlock) == -1) goto bad;
  159.  fdin = open_read(qmaillist);
  160.  if (fdin == -1) goto badlock;
  161.  fdout = open_trunc(qtemplist);
  162.  if (fdout == -1) goto badinlock;
  163.  if (chmod(qtemplist,0700) == -1) goto badoutinlock;
  164.  
  165.  flagwasthere = 0;
  166.  
  167.  substdio_fdbuf(&subin,read,fdin,subinbuf,sizeof(subinbuf));
  168.  substdio_fdbuf(&subout,write,fdout,suboutbuf,sizeof(suboutbuf));
  169.  for (;;)
  170.   {
  171.    if (getln(&subin,&subline,&match,'\n') == -1) goto badoutinlock;
  172.    if (!match) break; /* goodbye partial lines */
  173.    if (subline.len == str_len(target) + 2)
  174.      if (!str_diffn(subline.s + 1,target,subline.len - 2))
  175.        if (subline.s[0] == '&')
  176.         {
  177.          flagwasthere = 1;
  178.          if (!flagadd)
  179.            continue;
  180.         }
  181.    if (substdio_put(&subout,subline.s,subline.len) == -1) goto badoutinlock;
  182.   }
  183.  
  184.  if (flagadd && !flagwasthere)
  185.   {
  186.    if (substdio_puts(&subout,"&") == -1) goto badoutinlock;
  187.    if (substdio_puts(&subout,target) == -1) goto badoutinlock;
  188.    if (substdio_puts(&subout,"\n") == -1) goto badoutinlock;
  189.   }
  190.  if (substdio_flush(&subout) == -1) goto badoutinlock;
  191.  
  192.  close(fdout);
  193.  close(fdin);
  194.  if (rename(qtemplist,qmaillist) == -1) goto badlock;
  195.  if (chmod(qmaillist,0500) == -1) goto badlock;
  196.  
  197.  lock_un(fdlock);
  198.  
  199.  qmail_puts(&qqt,"***** Text inserted by ");
  200.  qmail_puts(&qqt,requestathost);
  201.  qmail_puts(&qqt,"\n*\n* ");
  202.  if (flagadd)
  203.    if (flagwasthere)
  204.     {
  205.      qmail_puts(&qqt,"Acknowledgment: ");
  206.      qmail_puts(&qqt,target);
  207.      qmail_puts(&qqt," was already a subscriber.\n");
  208.     }
  209.    else
  210.     {
  211.      qmail_puts(&qqt,"Acknowledgment: ");
  212.      qmail_puts(&qqt,target);
  213.      qmail_puts(&qqt," is now a subscriber.\n");
  214.     }
  215.  else
  216.    if (flagwasthere)
  217.     {
  218.      qmail_puts(&qqt,"Acknowledgment: ");
  219.      qmail_puts(&qqt,target);
  220.      qmail_puts(&qqt," is no longer a subscriber.\n");
  221.     }
  222.    else
  223.     {
  224.      qmail_puts(&qqt,"Hmmm, I don't see ");
  225.      qmail_puts(&qqt,target);
  226.      qmail_puts(&qqt," on the subscription list.\n* I'll let my owner know.\n");
  227.     }
  228.  qmail_puts(&qqt,"*\n*****\n");
  229.  return;
  230.  
  231. badoutinlock: close(fdout);
  232. badinlock: close(fdin);
  233. badlock: lock_un(fdlock);
  234. bad:
  235.  qmail_puts(&qqt,"***** Text inserted by ");
  236.  qmail_puts(&qqt,requestathost);
  237.  qmail_puts(&qqt,"\n*\n\
  238. * Oh no! Trouble making the new list. I'll let my owner know.\n\
  239. *\n\
  240. *****\n");
  241. }
  242.  
  243. void dobody(h) stralloc *h;
  244. {
  245.  qmail_put(&qqt,h->s,h->len);
  246.  if (case_starts(h->s,"subs")) subscribe(1);
  247.  if (case_starts(h->s,"unsu")) subscribe(0);
  248. }
  249.  
  250. stralloc hfbuf = {0};
  251. token822_alloc hfin = {0};
  252. token822_alloc hfrewrite = {0};
  253. token822_alloc hfaddr = {0};
  254.  
  255. void doheaderfield(h)
  256. stralloc *h;
  257. {
  258.  char *x;
  259.  switch(hfield_known(h->s,h->len))
  260.   {
  261.    case H_CONTENTLENGTH: /* SVR4 silliness */
  262.    case H_CONTENTTYPE:
  263.    case H_CONTENTTRANSFERENCODING: /* A-bombs 4.2.1.5.2 is idiotic */
  264.      return;
  265.    case H_FROM:
  266.      doordie(h,token822_parse(&hfin,h,&hfbuf));
  267.      doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,rwfrom));
  268.      break;
  269.    case H_REPLYTO:
  270.      doordie(h,token822_parse(&hfin,h,&hfbuf));
  271.      doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,rwrt));
  272.      break;
  273.    case H_SUBJECT:
  274.      x = h->s + hfield_skipname(h->s,h->len);
  275.      if (!case_diffb(x,4,"subs")) subjectaction = 1;
  276.      if (!case_diffb(x,4,"unsu")) subjectaction = 2;
  277.      break;
  278.   }
  279.  savedh_append(h);
  280. }
  281.  
  282. void main(argc,argv)
  283. int argc;
  284. char **argv;
  285. {
  286.  sig_pipeignore();
  287.  
  288.  if (!(listathost = argv[1])) die_usage();
  289.  if (!(requestathost = argv[2])) die_usage();
  290.  if (!(qmaillist = argv[3])) die_usage();
  291.  if (!(qmailrequest = argv[4])) die_usage();
  292.  if (!(qtemplist = argv[5])) die_usage();
  293.  if (!(owner = argv[6])) die_usage();
  294.  moreinfo = argv[7];
  295.  if (!(returnpath = env_get("NEWSENDER"))) die_usage();
  296.  if (!(dtline = env_get("DTLINE"))) die_usage();
  297.  
  298.  fdlock = open_append(qmailrequest);
  299.  if (fdlock == -1) die_nolock();
  300.  
  301.  numcommands = 0;
  302.  if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1) die_read();
  303.  if (!numcommands)
  304.   {
  305.    qmail_puts(&qqt,"***** Text inserted by ");
  306.    qmail_puts(&qqt,requestathost);
  307.    qmail_puts(&qqt,"\n*\n* ");
  308.    if (subjectaction)
  309.     {
  310.      qmail_puts(&qqt,"\
  311. Hmmm, no commands? Let me check the Subject line...\n*\n*****\n");
  312.      subscribe(subjectaction == 1);
  313.     }
  314.    else
  315.     {
  316.      qmail_puts(&qqt,"\
  317. I didn't see any commands. I presume this is a subscription request.\n\
  318. *\n*****\n");
  319.      subscribe(1);
  320.     }
  321.   }
  322.  
  323.  qmail_from(&qqt,returnpath);
  324.  qmail_to(&qqt,owner);
  325.  qmail_to(&qqt,target);
  326.  
  327.  switch(qmail_close(&qqt))
  328.   {
  329.    case 0: _exit(0);
  330.    case QMAIL_TOOLONG: die_qqperm();
  331.    default: die_qqtemp();
  332.   }
  333. }
  334.